from inqueue import db
from flask.ext.login import UserMixin
from datetime import datetime
from sqlalchemy import func

class DatabaseModel(db.Model):

  __abstract__ = True

  def save(self):
    db.session.add(self)
    db.session.commit()


class User(DatabaseModel, UserMixin):

  __tablename__ = 'users'
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(80))
  password = db.Column(db.String(80), nullable=False)
  email = db.Column(db.String(120), unique=True)

  carrier = db.Column(db.String(10))
  phone = db.Column(db.String(10))

  def pending_orders(self):
    return db.session.query(Order).filter(Order.user_id == self.id).\
                                   filter(func.date(Order.time_created) == func.date(datetime.utcnow())).\
                                   filter(Order.status == Order.STATUS_ACTIVE).all()

  def pending_and_ready_orders(self):
    return db.session.query(Order).filter(Order.user_id == self.id).\
                                  filter(func.date(Order.time_created) == func.date(datetime.utcnow())).\
                                  filter(Order.status != Order.STATUS_COMPLETED).all()

  def get_id(self):
    return unicode(self.id)

  def is_authenticated(self):
    return True

  def is_truck_owner(self):
    truck = None
    truck = db.session.query(Truck).filter(Truck.user_id == self.id).one()
    if truck:
      return True
    else:
      return False

class Truck(DatabaseModel):
  __tablename__ = 'trucks'

  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(80), unique=True)
  category = db.Column(db.String(10))
  description = db.Column(db.String(120))
  user_id = db.Column(db.Integer, db.ForeignKey('users.id'))  # admin for truck

  def current_menu(self):
    menu_items = db.session.query(MenuItem).filter(self.id == MenuItem.truck_id).all()
    return menu_items

  def all_my_food(self):
    all_my_food = db.session.query(Food).filter(self.id == MenuItem.truck_id,MenuItem.food_id == Food.id).all()
    return all_my_food

  def menu_for_day(self, date):
    menu_for_day = db.session.query(MenuItem).filter(self.id == MenuItem.truck_id, MenuItem.food_id == Food.id,
                                                 MenuItem.date == date)
    return menu_for_day

  def get_orders(self, status=None):
    query = db.session.query(Order).filter(self.id == MenuItem.truck_id).\
                                       filter(Order.menu_item_id == MenuItem.id)

    if status is not None:
      query = query.filter(Order.status == status)

    return query.all()

  def get_active_orders(self):
    return self.get_orders(Order.STATUS_ACTIVE)

  def get_ready_orders(self):
    return self.get_orders(Order.STATUS_READY)

  def get_completed_orders(self):
    return self.get_orders(Order.STATUS_COMPLETED)



class MenuItem(DatabaseModel):
  __tablename__ = 'menu_items'

  id = db.Column(db.Integer, primary_key=True)
  truck_id = db.Column(db.Integer, db.ForeignKey('trucks.id'))
  date = db.Column(db.Date(), nullable=False)
  food_id = db.Column(db.Integer, db.ForeignKey('food.id'))
  max_quantity = db.Column(db.Integer, nullable=False)

  @staticmethod
  def most_ordered():
    menu_item_counts = db.session.query(MenuItem, func.count('*')).filter(Order.menu_item_id == MenuItem.id).\
                                                                   filter(MenuItem.date == datetime.date(datetime.utcnow())).\
                                                                   group_by(MenuItem.id).all()

    most_item, max_count = None, -1e308
    for menu_item, count in menu_item_counts:
      if most_item is None or max_count < count:
        most_item, max_count = menu_item, count
    return most_item


  @staticmethod
  def least_remaining():
    menu_items = MenuItem.query.filter(MenuItem.date == datetime.date(datetime.utcnow())).all()

    least_item, least_amount = None, 1e308
    for menu_item in menu_items:
      if least_item is None or least_amount > menu_item.remaining_orders():
        least_item, least_amount = menu_item, menu_item.remaining_orders()
    return least_item


  @staticmethod
  def shortest_queue():
    menu_items = MenuItem.query.filter(MenuItem.date == datetime.date(datetime.utcnow())).all()

    least_item, least_wait = None, 1e308
    for menu_item in menu_items:
      if least_item is None or least_wait > menu_item.orders_in_queue():
        least_item, least_time = menu_item, menu_item.orders_in_queue()
    return least_item


  def remaining_orders(self):
    """
    Returns the number of remaining orders for the particular food item
    """
    num_orders = sum(i.quantity for i in db.session.query(Order).filter(Order.menu_item_id == self.id).all())
    return self.max_quantity - num_orders

  def orders_in_queue(self):
    """
    Returns the number of unprocessed orders
    """
    count_unprocessed_orders = db.session.query(Order).filter(Order.menu_item_id==self.id).\
                                                       filter(Order.status == Order.STATUS_ACTIVE).count()
    return count_unprocessed_orders


  def average_wait_time(self):

    time_diffs = [(order.time_completed-order.time_ready).seconds for order in db.session.query(Order).filter(Order.menu_item_id == self.id, Order.status == Order.STATUS_COMPLETED) if order.time_ready ]
    if len(time_diffs) > 0:
      return int(sum(time_diffs)/float(60*len(time_diffs)))
    else:
      return 0

  @property
  def food(self):
    return Food.query.get(self.food_id)

  @property
  def truck(self):
    return Truck.query.get(self.truck_id)
  
class Order(DatabaseModel):
  __tablename__ = 'orders'

  STATUS_ACTIVE = 'active'
  STATUS_READY = 'ready'
  STATUS_COMPLETED = 'completed'

  id = db.Column(db.Integer, primary_key=True)
  user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
  quantity = db.Column(db.Integer, nullable=False, default=1)
  menu_item_id = db.Column(db.Integer, db.ForeignKey('menu_items.id'))
  time_created = db.Column(db.DateTime())
  time_ready = db.Column(db.DateTime())
  time_completed = db.Column(db.DateTime())
  status = db.Column(db.String(20), nullable=False, default=STATUS_ACTIVE)

  def mark_completed(self):
    self.status = Order.STATUS_COMPLETED
    self.time_completed = datetime.utcnow()
    self.save()

  def mark_ready(self):
    self.status = Order.STATUS_READY
    self.time_ready = datetime.utcnow()
    self.save()

  @property
  def menu_item(self):
    return MenuItem.query.get(self.menu_item_id)

  @property
  def user(self):
    return User.query.get(self.user_id)

class Food(DatabaseModel):
  __tablename__ = 'food'
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(80))
  description = db.Column(db.String(120))


def create_data():

  db.drop_all()
  db.create_all()

  print "creating users..."
  create_users()
  print "creating trucks..."
  create_trucks()
  print "creating food..."
  create_food()
  print "creating menus..."
  create_menus()
#  print "creating orders..."
#  create_orders()

def create_users():
  #user_data = [("user{0}".format(i), 'user{0}@gmail.com'.format(i), 'password') for i in xrange(10)]
  #for name, email, password in user_data:
    #User(name=name, email=email, password=password).save()
  User(name="user1", email="user1@gmail.com", password="abcd").save()
  User(name="user2", email="user2@gmail.com", password="abcd").save()
  User(name="user3", email="user3@gmail.com", password="abcd").save()
  User(name="user4", email="user4@gmail.com", password="abcd").save()
  User(name="user5", email="user5@gmail.com", password="abcd").save()
  User(name="user20", email="user20@gmail.com", password="abcd").save()
  User(name="user21", email="user21@gmail.com", password="abcd").save()
  User(name="user22", email="user22@gmail.com", password="abcd").save()
  User(name="user23", email="user23@gmail.com", password="abcd").save()
  User(name="user24", email="user24@gmail.com", password="abcd").save()


def create_trucks():
  #truck_data = [('Truck{0}'.format(i), 'korean', 'korean food') for i in xrange(10)]
  #for name, category, description in truck_data:
  #  Truck(name=name, category=category, description=description).save()
  Truck(name="NomNom", category="Vietnamese", description="The best Vietnamese food on a truck", user_id=6).save()
  Truck(name="Seoul on Wheels", category="Korean", description="Authentic Korean cuisine", user_id=7).save()
  Truck(name="Tandoori", category="Indian", description="Best of Indian food", user_id=8).save()
  Truck(name="O Mi Ninja", category="Japanese", description="Eat Ramen like a ninja", user_id=9).save()
  Truck(name="McDonalds", category="Fast Food", description="American for you baby", user_id=10).save()


def create_food():
  #food_data = [('food{0}'.format(i), 'description{0}'.format(i)) for i in xrange(10)]
  #for name, description in food_data:
  #  Food(name=name, description=description).save()

  Food(name="Banh Mi Thit", description="").save()
  Food(name="Pho Noodle", description="").save()
  Food(name="Viet Springroll", description="").save()
  Food(name="Sweet and Sour Soup", description="").save()
  Food(name="Bulgogi - Short Rib", description="").save()
  Food(name="Rice Cake", description="").save()
  Food(name="Korean Salad", description="").save()
  Food(name="Seafood Pancake", description="").save()
  Food(name="Assam", description="").save()
  Food(name="Bihar", description="").save()
  Food(name="Chattisgarh", description="").save()
  Food(name="California Roll", description="").save()
  Food(name="Beef Ramen", description="").save()
  Food(name="Seafood Ramen", description="").save()
  Food(name="Vegan Ramen", description="").save()
  Food(name="Udon Noodle", description="").save()
  Food(name="Double Cheese Burger", description="").save()
  Food(name="French Fries", description="").save()
  Food(name="Caesar Salad", description="").save()


def create_menus():
  #menu_item_data = [(i, datetime.utcnow(), i, 200) for i in xrange(10)]
  #for truck_id, date, food_id, max_quantity in menu_item_data:
  #  MenuItem(truck_id=truck_id, date=date, food_id=food_id, max_quantity=max_quantity).save()
  date = datetime.date(datetime.utcnow())
  MenuItem(truck_id=1, date=date, food_id=1, max_quantity=25).save()
  MenuItem(truck_id=1, date=date, food_id=2, max_quantity=20).save()
  MenuItem(truck_id=1, date=date, food_id=3, max_quantity=15).save()
  MenuItem(truck_id=1, date=date, food_id=4, max_quantity=100).save()
  MenuItem(truck_id=2, date=date, food_id=5, max_quantity=50).save()
  MenuItem(truck_id=2, date=date, food_id=6, max_quantity=250).save()
  MenuItem(truck_id=2, date=date, food_id=7, max_quantity=80).save()
  MenuItem(truck_id=2, date=date, food_id=8, max_quantity=125).save()
  MenuItem(truck_id=3, date=date, food_id=9, max_quantity=25).save()
  MenuItem(truck_id=3, date=date, food_id=10, max_quantity=25).save()
  MenuItem(truck_id=3, date=date, food_id=11, max_quantity=25).save()
  MenuItem(truck_id=4, date=date, food_id=12, max_quantity=250).save()
  MenuItem(truck_id=4, date=date, food_id=13, max_quantity=25).save()
  MenuItem(truck_id=4, date=date, food_id=14, max_quantity=25).save()
  MenuItem(truck_id=4, date=date, food_id=15, max_quantity=200).save()
  MenuItem(truck_id=4, date=date, food_id=16, max_quantity=25).save()
  MenuItem(truck_id=5, date=date, food_id=17, max_quantity=25).save()
  MenuItem(truck_id=5, date=date, food_id=18, max_quantity=25).save()
  MenuItem(truck_id=5, date=date, food_id=19, max_quantity=25).save()

#def create_orders():
#  #order_data = [(i, 1, i, datetime.utcnow()) for i in xrange(10)]
#  #for user_id, quantity, menu_item_id, time_created in order_data:
#  #  Order(user_id=user_id, quantity=quantity, menu_item_id=menu_item_id, time_created=time_created).save()
#  time_created = datetime.utcnow()
#  Order(user_id=1, quantity=1, menu_item_id=1, time_created=time_created).save()
#  Order(user_id=2, quantity=1, menu_item_id=1, time_created=time_created).save()
#  Order(user_id=2, quantity=1, menu_item_id=2, time_created=time_created).save()
#  Order(user_id=2, quantity=1, menu_item_id=3, time_created=time_created).save()
#  Order(user_id=3, quantity=1, menu_item_id=2, time_created=time_created).save()
#  Order(user_id=4, quantity=1, menu_item_id=1, time_created=time_created).save()
#  Order(user_id=5, quantity=1, menu_item_id=1, time_created=time_created).save()
#  Order(user_id=5, quantity=1, menu_item_id=3, time_created=time_created).save()
#  Order(user_id=5, quantity=1, menu_item_id=2, time_created=time_created).save()




